package net.qhzw.geologr5.gis.service.system.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import net.qhzw.geologr5.gis.common.framework.utils.JsonResult;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

/***
 * 文件操作工具类
 */
@Slf4j
public class FileUtils {

    /**
     * zip文件解压
     *
     * @param inputFile   待解压文件夹/文件
     * @param destDirPath 解压路径
     */
    public static void zipUncompress(String inputFile, String destDirPath) throws FileNotFoundException {

        File srcFile = new File(inputFile);//获取当前压缩文件
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
        }
        //开始解压
        //构建解压输入流
        ZipInputStream zIn = new ZipInputStream(new FileInputStream(srcFile));
        ZipEntry entry = null;
        File file = null;
        OutputStream out = null;
        BufferedOutputStream bos = null;
        try {
            while ((entry = zIn.getNextEntry()) != null) {
                if (!entry.isDirectory()) {
                    file = new File(destDirPath, entry.getName());
                    if (!file.exists()) {
                        new File(file.getParent()).mkdirs();//创建此文件的上级目录
                    }
                    out = new FileOutputStream(file);
                    bos = new BufferedOutputStream(out);
                    int len = -1;
                    byte[] buf = new byte[1024];
                    while ((len = zIn.read(buf)) != -1) {
                        bos.write(buf, 0, len);
                    }
                }
            }
            log.info("解压完成");
        } catch (Exception e) {

        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }


    /**
     * 解压文件
     *
     * @param zipPath 要解压的目标文件
     * @param descDir 指定解压目录
     * @return 解压结果：成功，失败
     */
    @SuppressWarnings("rawtypes")
    public static JsonResult decompressZip(String zipPath, String descDir) {
        //解压之后的路径
        List<String> outPathList = new ArrayList<>();
        File zipFile = new File(zipPath);
        boolean flag = false;
        File pathFile = new File(descDir);
        if (!pathFile.exists()) {
            pathFile.mkdirs();
        }
        ZipFile zip = null;
        try {
            zip = new ZipFile(zipFile, Charset.forName("gbk"));//防止中文目录，乱码
            for (Enumeration entries = zip.entries(); entries.hasMoreElements(); ) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                String zipEntryName = entry.getName();
                InputStream in = zip.getInputStream(entry);
                //指定解压后的文件夹+当前zip文件的名称
                String outPath = (descDir + zipEntryName).replace("/", File.separator);
                //判断路径是否存在,不存在则创建文件路径
                File file = new File(outPath.substring(0, outPath.lastIndexOf(File.separator)));
                if (!file.exists()) {
                    file.mkdirs();
                }
                //判断文件全路径是否为文件夹,如果是上面已经上传,不需要解压
                if (new File(outPath).isDirectory()) {
                    continue;
                }
                //保存文件路径信息（可利用md5.zip名称的唯一性，来判断是否已经解压）
                log.info("当前zip解压之后的路径为：{}", outPath);
                outPathList.add(outPath);
                OutputStream out = new FileOutputStream(outPath);
                byte[] buf1 = new byte[2048];
                int len;
                while ((len = in.read(buf1)) > 0) {
                    out.write(buf1, 0, len);
                }
                in.close();
                out.close();
            }
            flag = true;
            zip.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (flag) {
            return JsonResult.success(JSON.toJSONString(outPathList), "解压成功");
        }
        return JsonResult.error();
    }

    /**
     * 根据路径删除指定的目录或文件，无论存在与否
     *
     * @param sPath 要删除的目录或文件
     * @return 删除成功返回 true，否则返回 false。
     */
    public static boolean deleteFolder(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 判断目录或文件是否存在
        if (!file.exists()) {  // 不存在返回 false
            return flag;
        } else {
            // 判断是否为文件
            if (file.isFile()) {  // 为文件时调用删除文件方法
                return deleteFile(sPath);
            } else {  // 为目录时调用删除目录方法
                return deleteDirectory(sPath);
            }
        }
    }

    /**
     * 删除单个文件
     *
     * @param sPath 被删除文件的文件名
     * @return 单个文件删除成功返回true，否则返回false
     */
    private static boolean deleteFile(String sPath) {
        boolean flag = false;
        File file = new File(sPath);
        // 路径为文件且不为空则进行删除
        if (file.isFile() && file.exists()) {
            file.delete();
            flag = true;
        }
        return flag;
    }

    /**
     * 删除目录（文件夹）以及目录下的文件
     *
     * @param sPath 被删除目录的文件路径
     * @return 目录删除成功返回true，否则返回false
     */
    private static boolean deleteDirectory(String sPath) {
        //如果sPath不以文件分隔符结尾，自动添加文件分隔符
        if (!sPath.endsWith(File.separator)) {
            sPath = sPath + File.separator;
        }
        File dirFile = new File(sPath);
        //如果dir对应的文件不存在，或者不是一个目录，则退出
        if (!dirFile.exists() || !dirFile.isDirectory()) {
            return false;
        }
        boolean flag = true;
        //删除文件夹下的所有文件(包括子目录)
        File[] files = dirFile.listFiles();
        for (int i = 0; i < files.length; i++) {
            //删除子文件
            if (files[i].isFile()) {
                flag = deleteFile(files[i].getAbsolutePath());
                if (!flag) break;
            } //删除子目录
            else {
                flag = deleteDirectory(files[i].getAbsolutePath());
                if (!flag) break;
            }
        }
        if (!flag) return false;
        //删除当前目录
        if (dirFile.delete()) {
            return true;
        } else {
            return false;
        }
    }


    //存放符合规定的文件
    private static final List<File> fileArrayList = new ArrayList<>();

    public static File[] getFiles(File file, String... ext) {
        //将当前目录下的所有文件和文件夹都添加到files中
        File[] files = file.listFiles((dir, name) -> {
            //如果文件夹返回true
            if (new File(dir, name).isDirectory()) {
                return true;
            }
            //如果指定了文件类型 , 进行文件筛选
            if (ext != null && ext.length > 0) {
                for (String s : ext) {
                    //如果文件符合规则 , 返回true
                    if (name.toLowerCase().endsWith(s.toLowerCase())) {
                        return true;
                    }
                }
            } else {
                //没有规定文件类型 , 所有文件都返回true
                return true;
            }
            return false;
        });
        //如果files不为null , 遍历files . 如果files为null , 遍历空数组.
        for (File f : files != null ? files : new File[0]) {
            //如果f不是文件夹 , 添加到指定list中
            if (!f.isDirectory()) {
                fileArrayList.add(f);
                continue;
            }
            getFiles(f, ext);
        }
        //将list转换成File数组并进行返回
        return fileArrayList.toArray(new File[0]);
    }

    /***
     * 移动指定文件夹内的全部文件
     * @param from
     * @param to
     * @throws Exception
     */
    public static void fileMove(String from, String to) throws Exception {
        File dir = new File(from);
        File[] files = dir.listFiles();// 将文件或文件夹放入文件集
        if (files == null)// 判断文件集是否为空
            return;
        File moveDir = new File(to);// 创建目标目录
        if (!moveDir.exists()) {// 判断目标目录是否存在
            moveDir.mkdirs();// 不存在则创建
        }
        for (int i = 0; i < files.length; i++) {// 遍历文件集
            if (files[i].isDirectory()) {// 如果是文件夹或目录,则递归调用fileMove方法，直到获得目录下的文件
                fileMove(files[i].getPath(), to + "\\" + files[i].getName());// 递归移动文件
                files[i].delete();// 删除文件所在原目录
            }
            File moveFile = new File(moveDir.getPath() + "\\"// 将文件目录放入移动后的目录
                    + files[i].getName());
            if (moveFile.exists()) {// 目标文件夹下存在的话，删除
                moveFile.delete();
            }
            files[i].renameTo(moveFile);// 移动文件
            log.info("[{}] 移动成功", files[i]);
        }

    }

    /***
     * 移动文件
     * @param filename 文件名
     * @param oldpath 旧文件地址
     * @param newpath  新文件地址
     * @param cover  存在同名文件true:覆盖；false:不覆盖
     */
    public static void changeDirectory(String filename, String oldpath, String newpath, boolean cover) {
        if (!oldpath.equals(newpath)) {
            File oldfile = new File(oldpath);
            File newfile = new File(newpath);
            if (newfile.exists()) {// 若在待转移目录下，已经存在待转移文件
                if (cover) {// 覆盖
                    oldfile.renameTo(newfile);
                } else {
                    System.out.println("在新目录下已经存在：" + filename);
                }
            } else {
                oldfile.renameTo(newfile);
            }
        }
    }


    /***
     * 移动文件
     * @param fileName
     * @param destinationFloderUrl
     * @return
     */
    public static boolean removeFile(String fileName, String destinationFloderUrl) {
        File file = new File(fileName);
        File destFloder = new File(destinationFloderUrl);
        //检查目标路径是否合法
        if (destFloder.exists()) {
            if (destFloder.isFile()) {
                log.error("目标路径是个文件，请检查目标路径！");
                return false;
            }
        } else {
            if (!destFloder.mkdirs()) {
                log.error("目标文件夹不存在，创建失败！");
                return false;
            }
        }
        //检查源文件是否合法
        if (file.isFile() && file.exists()) {
            String destinationFile = destinationFloderUrl + "/" + file.getName();
            if (!file.renameTo(new File(destinationFile))) {
                log.error("移动文件失败！");
                return false;
            }
        } else {
            log.error("要备份的文件路径不正确，移动失败！");
            return false;
        }
        log.info("已成功移动文件" + file.getName() + "到" + destinationFloderUrl);
        return true;
    }

    /***
     *把字节数B转化为KB、MB、GB
     * @param size
     * @return
     */
    private static String getFileSize(long size) {
        //如果字节数少于1024，则直接以B为单位，否则先除于1024，后3位因太少无意义
        if (size < 1024) {
            return String.valueOf(size) + "B";
        } else {
            size = size / 1024;
        }
        //如果原字节数除于1024之后，少于1024，则可以直接以KB作为单位
        //因为还没有到达要使用另一个单位的时候
        //接下去以此类推
        if (size < 1024) {
            return String.valueOf(size) + "KB";
        } else {
            size = size / 1024;
        }
        if (size < 1024) {
            //因为如果以MB为单位的话，要保留最后1位小数，
            //因此，把此数乘以100之后再取余
            size = size * 100;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "MB";
        } else {
            //否则如果要以GB为单位的，先除于1024再作同样的处理
            size = size * 100 / 1024;
            return String.valueOf((size / 100)) + "."
                    + String.valueOf((size % 100)) + "GB";
        }
    }


}
